import React, {Component} from 'react';
import Menu from "./menu";
import Navbar from "./navbar";
import $ from "jquery"
import TableForWeighValue from "./TableForWeighValue";
import TableForDynamic from "./TableForDynamic";
import {value, volume, weight} from "./Const";
import TableForFib from "./TableForFib";

let before = false;
let pause = false;
let reset = false;
const maxNum = 100;
// s 是字符串
const checkNumber = (s) => {
    return Number(s, 10).toString() === s;
}
const getInput = (id) => {
        let temp = document.getElementById(id).value;
        return temp.split(",").map((value) => parseInt(value));

}
const weightID = "weight";
const valueID = "value";

class Graph extends Component {
    constructor() {
        super();
        this.state = {

            reset: false,

            current: -1,

            algo: 0,
            offset: 0,
            animation_stop: true,
            time: 500,
            // 随机选择的num
            selectNum: 0,
            // 最多可以选择到多少N

            select: false,
            listN: [],
            nowLine: -1,
            nowColumn: -1,
            rows: [],
            listVolume: [],
            fibValue: [0, 1],
            v:99999,

        }
        this.wvIndex = -1;
        this.coinValueIndex = -1;
        this.nowIndex=-1;
        this.values = [];
        this.weights = [];
        this.volume = 5;
    }


    handlePaused = (flag) => {
        // this.setState({isPaused: flag});
        before = pause;
        pause = flag;
    }


    handlePausedForLoop = () => {
        before = false;
        pause = true;
    }

    handleGenerate = async () => {
        let inputElement;
        await this.realOnReset();
        let algo = this.state.algo;
        if (algo === 0) {
            let random1 = Math.floor(Math.random() * volume.length);
            let random2 = Math.floor(Math.random() * value.length);
            await this.setCustomState({selectNum: random1});
            $('#' + weightID).val(weight[random2].reduce((a, b) => a + "," + b));
            $('#' + valueID).val(value[random2].reduce((a,b)=>a+","+b));

        } else {
            let random = Math.floor(Math.random() * 15);
            await this.setCustomState({selectNum: random});
            await this.stateAwait();
        }
    }

    handleSpeed = (speed) => {
        let time;
        if (speed >= 80) {

            time = 900 - 9 * speed + 1;

        }
        else {
            time = 1800 - 8 * speed;
        }
        this.setState({time})
    }

    changeSelect = () => {
        let select = !this.state.select;
        this.setState({select});
    }

    realOnReset = async () => {
        pause = true;

        this.changeSelect();
        this.onReset();
        this.setState({changed: !this.state.changed});

        await sleep(1);
    }

    onReset = () => {
        pause = true;

        this.setState({reset: true, setGreenFlag: false,
            listN : [],
            nowLine: -1,
            nowColumn: -1,
            rows: [],
            fibValue: [0, 1],
            listVolume: [],
            v:99999
        });
        this.wvIndex = -1;
        this.weights = this.values = [];
        // this.volume = 5;

        reset = true;
        this.state.vertices = [];

        $("#img").css({
                        scale: "1",
                        transform: "scale(1)",
                        left: "0",
                        top: "10px",
                      });
        pause = before = false;
    }

    handleInput = async () => {

        try {
            if (this.state.algo === 0) {
                if (this.state.algo === 0) {
                    this.weights = getInput(weightID);
                this.weights.splice(0, 0, 0);

                await this.stateAwait();
                }

            this.values = getInput(valueID);
            if (this.state.algo === 0)
                this.values.splice(0, 0, 0);
            await this.stateAwait(); }
            else if (this.state.algo === 1) {

            }
            else {
            }
        } catch (e) {

        }

    }

    setAlgo = async (pos, val) => {
        if (pos === 0) {
            await this.realOnReset();
            await this.setCustomState({ algo: val});


        }
    }

    stateAwait = async () => {
        await sleep(1);
    }

    setVolume = async (val) => {
        await this.realOnReset();
        this.volume = parseInt(val) + 5;
        await this.stateAwait();
    }

    addNumber = async ()=>{
        if (!before) {
            await this.onReset();
            await this.handleInput();

            await this.addNumberTemp();
            this.changeSelect();
            pause = before = false;

        }
    }

    addNumberTemp = async () => {
        this.setState({reset: false});
        reset = false;

        if (this.state.algo === 0) {
            await this._01Knapsack();
        } else if (this.state.algo === 1) {
            await this.fib();
        } else {

        }

    }

    generateN = (n, bias=0) => {
        let list = [];
        for (let i = 0; i < n; i++) {
            list.push(i + bias);
        }
        return list;
    }

    setCustomState = async (d, mode=0) => {
        this.setState(d);
        if (mode === 0)
            await this.stateAwait();
        else
            await sleep(this.state.time);
    }

    coin = async ()=> {

    }

    _01Knapsack = async () => {
        let listN = this.generateN(this.weights.length - 1, 1);
        await this.setCustomState({listN});
        let listVolume = this.generateN(this.volume + 1);
        await this.setCustomState({listVolume});

        let temp = [];
        for (let i = 0; i < this.volume + 1; i++) {
            temp.push(0);
        }
        let rows = [...this.state.rows];
        rows.push(temp);
        await this.setCustomState({rows});

        let f = new Array();
        for (let i = 0; i < maxNum; i++) {
            f[i] = new Array();
            for (let j = 0; j < maxNum; j++) {
                f[i][j] = 0;
            }
        }
        const max = (a, b) => {
            if (a > b)
                return a;
            else
                return b;
        }
        for (let i = 1; i < this.weights.length ; i++) {
            this.wvIndex = i - 1;
            await sleep(this.state.time);
            rows = [...rows];
            rows.push([0]);
            for (let j = 1; j <= this.volume; j++) {
                if (j < this.weights[i])
                    f[i][j] = f[i-1][j];
                else
                    f[i][j] = max(f[i-1][j], f[i-1][j-this.weights[i]] + this.values[i]);
                rows[i].push(f[i][j]);
                await this.setCustomState({nowLine: i, nowColumn: j, v: this.weights[i]}, 1);
                await this.setCustomState({rows});
                this.changeSelect();
                this.handlePausedForLoop();
                await sleep(this.state.time);
            }
        }

    }

    addTextToConsole = (text) => {
        let consoleElement = document.getElementById("console");
        consoleElement.insertAdjacentHTML("beforeEnd", `<p class="text-warning m-0"><span class="text-light">-></span> ${text}</p>`);
        consoleElement.scrollTo(0, consoleElement.offsetHeight);
}

    clearConsole = () => {
        let consoleElement = document.getElementById("console");
        consoleElement.innerHTML = "";
}

    fib = async () => {
        console.log(this.volume);
        console.log(this.generateN(this.volume + 1));
        await this.setCustomState({listN: this.generateN(this.volume + 1)});

        let fibValue = [...this.state.fibValue];
        for (let i = 2; i <= this.volume; i++) {
            fibValue.push(fibValue[fibValue.length - 1] + fibValue[fibValue.length - 2]);
            await sleep(this.state.time);
            this.nowIndex = i;
            await this.setCustomState({fibValue: [...fibValue]},1);

        }
    }

    algoDisplay = () => {
        let display;

        if (this.state.algo === 0) {
            display =  (
                <React.Fragment>
                    <TableForWeighValue
                        listN = {this.state.listN}
                        nowIndex = {this.wvIndex}
                        tableName = {"Weights and Values"}
                        reset = {reset}
                        weights = {this.weights}
                        values = {this.values}
                    />
                    <TableForDynamic
                        listN={this.state.listVolume}
                        nowLine={this.state.nowLine}
                        nowColumn={this.state.nowColumn}
                        v={this.state.v}
                        rows = {this.state.rows}
                        reset={reset}
                        tableName={"Knapsack Table"}
                    />
                </React.Fragment>
            )
        }
        // else if (this.state.algo === 1){
        //     display = (
        //       <React.Fragment>
        //           <CoinTable
        //             listN = {this.values}
        //             nowIndex = {this.coinValueIndex}
        //             reset = {reset}
        //             tableName={"Coin type"}
        //           />
        //
        //
        //           {/*<CoinValueTable/>*/}
        //
        //           <div className="w-100"></div>
        //           <div className="row v-align justify-content-center" >
        //               <div className="bg-dark p-3" id="console"
        //                    style={{width: "50%", height: "calc(100vh - 470px)", overflow: "none", overflowY: "scroll"}}></div>
        //           </div>
        //
        //       </React.Fragment>
        //     );
        // }
        else {
            display = (
              <React.Fragment>
                  <TableForFib
                    listN={this.state.listN}
                    nowIndex={this.nowIndex}
                    value={this.state.fibValue}
                    tableName={"Fibonacci generating table"}
                    reset={reset}
                  />
              </React.Fragment>
            );
        }

        return display;
    }


    render = () =>  {
        // $('body').css({"overflow-x": "hidden"});

        return (
            <div style={{
                overflow: "hidden",
                }}>
                <Navbar
                    name={"Dynamic programming"}
                />
                <Menu
                    handlePaused = {this.handlePaused}
                    select = {this.state.select}

                    onChange = {this.realOnReset}

                    MaxN = {this.state.MaxN}
                    selectNum = {this.state.selectNum}
                    onGenerate = {this.handleGenerate}
                    algo={this.state.algo}
                    handleSpeed = {this.handleSpeed}
                    setVolume = {this.setVolume}
                    setAlgo={this.setAlgo}
                    onStart={this.addNumber}
                    onReset={this.realOnReset}


                />

                {this.algoDisplay()}

            </div>
        );
    }
}

// const requestAnimationFrame = window.requestAnimationFrame
// || window.mozRequestAnimationFram
// || window.webkitRequestAnimationFrame
// || window.msRequestAnimationFrame
// || function(callback){ window.setTimeout(callback, 1000/ 60)}

const cancelAnimationFrame = window.cancelAnimationFrame
|| window.mozCancelAnimationFrame;

let allRef = null;

function animateTimeout(cb,time){

	let i = 0;

    let myRef = null;
    let rememberTime = time;
	myRef = requestAnimationFrame(function fn(){
        if (pause)
            time = 100000000000;
        else
            time = rememberTime;
		if(i > Math.floor(60 / (1000/time)) || reset){
			cb();
			cancelAnimationFrame(myRef);
            // return ;
		}
		i++;

		myRef = requestAnimationFrame(fn)
	})
}


function sleep(ms) {
    return new Promise(resolve => animateTimeout(resolve, ms));
}
export default Graph;